Skip to content

Longitudinal metrics workflow Fix #200#297

Closed
jpillai00 wants to merge 10 commits into
mainfrom
add/metrics-longitudinal
Closed

Longitudinal metrics workflow Fix #200#297
jpillai00 wants to merge 10 commits into
mainfrom
add/metrics-longitudinal

Conversation

@jpillai00
Copy link
Copy Markdown
Contributor

@jpillai00 jpillai00 commented Apr 10, 2026

draft for now.. need to test this! & this is based off #282

Extends the longitudinal pipeline to compute derivative metrics (ALFF, fALFF, ReHo, smoothing, z-scoring, and atlas-based timeseries extraction) on longitudinal-space BOLD, mirroring the existing cross-sectional metrics workflow.

Key changes:

bids/longitudinal.py

  • added LongitudinalMetricsInputs TypedDict, resolve_longitudinal_metrics (resolves per-regressor regressed/cleaned BOLD and brain mask from longitudinal derivatives), and export_longitudinal_metrics (delegates to existing export_metrics)

orchestration/longitudinal.py

  • added process_metrics which resolves inputs, reads TR from nifti header, runs single_session_metrics, and exports outputs; added metrics and atlas_files parameters to run()

cli/longitudinal.py

  • added --metrics flag and --atlas argument (defaulting to schaefer_200); TR and FWHM are not exposed as CLI params and use hardcoded defaults (read from header and 6mm respectively) to match cross-sectional behavior

No changes to workflows/metrics.py - single_session_metrics already works generically for both cross-sectional and longitudinal space.

@jpillai00 jpillai00 linked an issue Apr 10, 2026 that may be closed by this pull request
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 10, 2026

Coverage

Coverage Report
FileStmtsMissCoverMissing
rbc
   __init__.py10100% 
   context.py25868%70, 75–77, 79–80, 93–94
   metadata.py560100% 
rbc/bids
   __init__.py90100% 
   _schema.py585499%776, 782, 790, 1101
   anatomical.py24387%44, 47–48
   builder.py72790%233–235, 362, 364–365, 386
   functional.py43588%46–49, 84
   longitudinal.py47295%236, 272
   metrics.py23195%44
   qc.py170100% 
   query.py674237%103–107, 121–125, 127–128, 130–135, 137, 139, 153, 159–165, 198, 207, 209–216, 225, 257, 266–267
   session.py470100% 
rbc/cli
   __init__.py10100% 
   all.py49295%84, 109
   anatomical.py25292%47, 63
   base.py71987%56, 62, 123–125, 131–133, 156
   functional.py33293%67, 87
   longitudinal.py34294%54, 74
   main.py420100% 
   metrics.py42295%77, 95
   qc.py25292%45, 61
rbc/core
   __init__.py30100% 
   common.py261253%43–45, 62–70
   fileops.py27485%69–72
   fsl2itk.py420100% 
   nifti.py192597%236–237, 244–245, 524
   niwrap.py56198%58
rbc/core/anatomical
   __init__.py40100% 
   registration.py15473%59, 151, 166, 183
   segmentation.py24866%64, 74–76, 92, 114, 125, 141
rbc/core/functional
   __init__.py130100% 
   coregistration.py7271%44, 55
   despiking.py7357%32, 36–37
   distortion.py1304069%269–271, 321, 324, 332–335, 341–346, 349, 352–353, 356, 365–369, 375–376, 387–388, 391, 397, 443–444, 447, 455, 461, 470–471, 474, 484, 491
   erosion.py32196%50
   initialization.py9455%35, 42–43, 63
   masking.py342526%53, 55–56, 58–59, 62–65, 69, 91, 134, 183, 197, 208, 223, 233, 249, 258, 271, 285, 296, 306, 319, 328
   motion.py573735%62, 64–67, 69, 71, 73, 76–77, 83–84, 86–87, 95–97, 99, 102, 105, 107, 124–125, 135–138, 159, 169, 171–172, 175, 177–179, 181, 183
   nuisance.py816025%78, 80–85, 87, 89–90, 93, 96–98, 100–102, 104–110, 112–116, 118, 163, 165, 167, 170–171, 173–175, 178, 181–182, 185–187, 190–193, 197, 203–205, 207, 235, 243, 269, 278, 307, 316, 322
   regressors.py89693%163, 193, 325–328
   resampling.py544320%37–42, 74–76, 78, 80–81, 85–87, 90, 93, 105, 107–108, 112, 114, 150–152, 154–155, 159, 161–162, 167–169, 173–174, 177, 180, 187, 199, 201–202, 207, 209
   timing.py161131%46–47, 49–53, 58, 60, 66–67
rbc/core/longitudinal
   __init__.py10100% 
   transform.py46784%106–107, 165–168, 170
rbc/core/metrics
   __init__.py30100% 
   alff.py90198%265
   reho.py660100% 
   smoothing.py7357%36, 42–43
   standardization.py271159%64, 66–68, 70, 72–75, 77–78
   timeseries.py57198%120
rbc/core/qc
   __init__.py60100% 
   dvars.py260100% 
   motion.py310100% 
   registration.py410100% 
   xcp.py410100% 
rbc/orchestration
   __init__.py32293%90, 93
   all.py41978%131–132, 137, 145, 153–154, 171, 173–174
   anatomical.py372240%49–52, 57–58, 60–63, 85–87, 89–90, 94, 101, 104, 109–110, 116, 118
   functional.py411270%124–126, 128–129, 133, 139, 142, 147–148, 157, 159
   longitudinal.py701184%129–130, 132, 134–137, 143, 200, 234–235
   metrics.py463034%32–35, 38–40, 67, 75–76, 100–102, 104–106, 110, 118–121, 123–124, 130–132, 137, 145, 152, 154
   qc.py340100% 
rbc/workflows
   __init__.py100100% 
   anatomical.py471959%90–93, 97–102, 107, 177–180, 182–184, 188
   functional.py1116640%115–116, 124, 129–130, 138, 209–210, 213–214, 217–218, 221, 224–227, 237–239, 249–250, 253, 256, 259–260, 268–269, 276–277, 284–285, 292–293, 296–298, 301–304, 316–317, 329, 331–334, 337–338, 347–348, 356, 363, 455, 462, 465, 470, 472–474, 476–477, 483–484, 490
   metrics.py411856%80, 83–84, 93–94, 99–102, 105–108, 112–115, 119
   qc.py553438%88–89, 92–93, 96, 99, 102–107, 110, 119–121, 125–128, 130–134, 136–137, 139–141, 144, 161, 167, 169
rbc_resources
   __init__.py380100% 
TOTAL330160581% 

Tests Skipped Failures Errors Time
729 0 💤 0 ❌ 0 🔥 10.938s ⏱️

@jpillai00 jpillai00 force-pushed the add/metrics-longitudinal branch from 4f4555a to e1e80a1 Compare April 10, 2026 20:11
@jpillai00 jpillai00 force-pushed the add/metrics-longitudinal branch from e1e80a1 to af17925 Compare April 10, 2026 20:18
@jpillai00 jpillai00 marked this pull request as ready for review April 13, 2026 15:39
Copilot AI review requested due to automatic review settings April 13, 2026 15:39
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@nx10
Copy link
Copy Markdown
Contributor

nx10 commented Apr 13, 2026

Thanks @jpillai00 — reusing single_session_metrics unchanged for longitudinal space is the right call. Closing as superseded by #301; Stage 6 rewrites this against the new CLI shape (boolean --metrics goes away, becomes rbc longitudinal metrics with --atlas/--fwhm mirroring cross-sectional defaults). Port commits will carry Co-authored-by: Janhavi Pillai trailers.

Closed as part of #301 Stage 0.

@nx10 nx10 closed this Apr 13, 2026
nx10 added a commit that referenced this pull request Apr 16, 2026
Implement rbc longitudinal metrics: resolve per-regressor
regressed_bold/cleaned_bold + brain mask from space-longitudinal
functional derivatives, read TR from NIfTI header, and call
single_session_metrics unchanged. Reuse cross-sectional export_metrics
for BIDS output naming.

Co-authored-by: Janhavi Pillai <janhavipillai3@gmail.com>
nx10 added a commit that referenced this pull request Apr 17, 2026
)

* Add longitudinal metrics orchestration (port from #297)

Resolve per-regressor regressed/cleaned BOLD and brain mask from
space-longitudinal derivatives, read TR from NIfTI header, call
single_session_metrics unchanged. Reuse cross-sectional export_metrics
for BIDS naming.

Co-authored-by: Janhavi Pillai <janhavipillai3@gmail.com>

* Add longitudinal QC, all pipeline, and full_pipeline tests

QC: Dice/Jaccard between anat and BOLD brain masks in longitudinal
space, pass threshold Dice >= 0.85. Viz tracked in #303/#304.

All pipeline: template -> anat -> func -> metrics -> qc. Template
writes to disk cross-session; per-session stages hand off func outputs
in-memory. process_anat/process_func now return workflow outputs.

CLI: Add --regressor and --task to `rbc longitudinal all`.

Tests: Tier-4 full_pipeline tests for metrics, QC, and all-vs-sequential
equivalence under tests/full_pipeline/longitudinal/.

* Fix anat groupby dropping mask rows in longitudinal resolve

T1w suffix filter in run() excluded masks from the DataFrame passed to
process_anat, so resolve_longitudinal_anat couldn't find them. Drop the
filter. Pre-existing Stage 4 bug exposed by new tests.

* Add --regressor to longitudinal metrics CLI

Replace DataFrame-based discovery (queried a non-existent 'reg' column)
with explicit --regressor, matching cross-sectional.

* Fix longitudinal all test fixture missing --session-label

Fixture ran cross-sectional func only for ses-test but invoked
`rbc longitudinal all` without --session-label, so it iterated ses-retest
(no func derivatives) and crashed on an empty BOLD DataFrame.

* Apply only participant filter to template discovery in all pipeline

Template needs all sessions to find multi-session subjects. Session/task
filters apply only to per-session stages, not discover_template_inputs.

* Clean up tech debt: TR validation, FS auth, QC load_table

TR: Promote resolve_tr/warn_implausible_tr to public API. Replace
_read_header_tr with _read_derivative_tr that pipes through resolve_tr
for validation and plausibility warnings. Add --tr override to
longitudinal metrics CLI.

FS auth: Rename _setup_freesurfer_auth -> setup_freesurfer_auth, export
from template.py, import at module level in all.py.

QC: Replace manual concat of session.anat + session.func + tpl_df with
load_table, matching cross-sectional qc.py.

---------
Co-authored-by: Janhavi Pillai <janhavi.pillai@gmail.com>
@kaitj kaitj deleted the add/metrics-longitudinal branch May 20, 2026 23:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add metrics longitudinal workflow

3 participants